// Copyright 2022 NullPTR. All Rights Reserved.


#include "FTTFUtils.h"

namespace SDFGen
{
	std::map<std::string, FT_Face> FTTFUtils::FTFaceMap;
	
	FTTFUtils::FTTFUtils()
	{
	}

	FTTFUtils::~FTTFUtils()
	{
	}

	void FTTFUtils::Init()
	{
		FT_Error Error = FT_Init_FreeType(&FTLibrary);
		if (Error)
		{
			UE_LOG(LogTemp, Error, TEXT("FreeType Library init failed."));
		}
		else
		{
			UE_LOG(LogTemp, Log, TEXT("FreeType Library init succ."));
		}
	}

	void FTTFUtils::Release()
	{
		auto iter(FTFaceMap.begin());
		for (; iter != FTFaceMap.end(); ++iter)
		{
			FT_Done_Face(iter->second);
		}
		FTFaceMap.clear();
	
		FT_Done_FreeType(FTLibrary);
	}

	void FTTFUtils::RenderToFontBitmap(FRGBABitmap* FontBitmap, FontMetrics* Metrics, const FString& single_char, const FString& font_path, int font_size)
	{
		check(FontBitmap);
		
		FT_Face face;

		int temp_index = 0;
		font_path.FindLastChar(TEXT('/'), temp_index);
		std::string face_name = TCHAR_TO_UTF8(*font_path.RightChop(temp_index));

		auto iter = FTFaceMap.find(face_name);
		if (iter == FTFaceMap.end())
		{
			// 从font_path字符串中提取文件名
			// 以文件名为索引，建立Face Map
			// 如果Face不存在，则加载
	
			FT_Error error = FT_New_Face(FTLibrary,
										 TCHAR_TO_UTF8(*font_path),
										 0,
										 &face);

			if (error == FT_Err_Unknown_File_Format)
			{
				//std::cerr << "the font file could be opened and read, but it appears that its font format is unsupported" << std::endl;
				return;
			}
			else if (error)
			{
				//std::cerr << "another error code means that the font file could not be opened or read, or that it is broken" << std::endl;
				return;
			}

			FTFaceMap[face_name] = face;
		}
		else
		{
			face = iter->second;
		}
	
		FT_Select_Charmap(face, FT_ENCODING_UNICODE);
		
		FT_Set_Char_Size(face, 0, font_size * 64, 300, 300);
		FT_Set_Pixel_Sizes(face, 0, font_size);
	
		UTF16CHAR *charcode = TCHAR_TO_UTF16(*single_char);
		FT_UInt glyph_index = FT_Get_Char_Index(face, *charcode);
		FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
		FT_Render_Glyph(face->glyph, FT_RENDER_MODE_NORMAL);

		FT_Bitmap bitmap = face->glyph->bitmap;
		int extsize = 50;
		int image_height = bitmap.rows + extsize * 2;
		int image_width = bitmap.width + extsize * 2;

		FontBitmap->Create(image_width, image_height);
		
		int offsetx = extsize;
		int offsety = extsize;
		unsigned char c = 0;
		for (int row = 0; row < image_height; ++row)
		{
			for (int col = 0; col < image_width; ++col)
			{
				if (col < offsetx || row < offsety) {
					c = 0;
				} else {

					int x = col - offsetx;
					int y = row - offsety;

					if (x >= static_cast<int>(bitmap.width) || y >= static_cast<int>(bitmap.rows)) {
						c = 0;
					} else {
						c = bitmap.buffer[y * bitmap.width + x];
					}
				}

				FontBitmap->SetRGB(col, row, c, c, c);
			}
		}

		{
			const FT_Glyph_Metrics& Glyph_Metrics = face->glyph->metrics;

			Metrics->AdvanceH = static_cast<float>(Glyph_Metrics.horiAdvance) / Glyph_Metrics.width;
			Metrics->AdvanceV = static_cast<float>(Glyph_Metrics.vertAdvance) / Glyph_Metrics.height;
			Metrics->BearingH = FVector2D(static_cast<float>(Glyph_Metrics.horiBearingX) / Glyph_Metrics.width,
				static_cast<float>(Glyph_Metrics.horiBearingY) / Glyph_Metrics.height);
			Metrics->BearingV = FVector2D(static_cast<float>(Glyph_Metrics.vertBearingX) / Glyph_Metrics.width,
				static_cast<float>(Glyph_Metrics.vertBearingY) / Glyph_Metrics.height);
		}
	}

	void FTTFUtils::RenderToFontBitmap(FImage* FontBitmap, FontMetrics* Metrics, const FString& single_char,
		const FString& font_path, int font_size)
	{
			check(FontBitmap);
		
		FT_Face face;

		int temp_index = 0;
		font_path.FindLastChar(TEXT('/'), temp_index);
		std::string face_name = TCHAR_TO_UTF8(*font_path.RightChop(temp_index));

		auto iter = FTFaceMap.find(face_name);
		if (iter == FTFaceMap.end())
		{
			// 从font_path字符串中提取文件名
			// 以文件名为索引，建立Face Map
			// 如果Face不存在，则加载
	
			FT_Error error = FT_New_Face(FTLibrary,
										 TCHAR_TO_UTF8(*font_path),
										 0,
										 &face);

			if (error == FT_Err_Unknown_File_Format)
			{
				//std::cerr << "the font file could be opened and read, but it appears that its font format is unsupported" << std::endl;
				return;
			}
			else if (error)
			{
				//std::cerr << "another error code means that the font file could not be opened or read, or that it is broken" << std::endl;
				return;
			}

			FTFaceMap[face_name] = face;
		}
		else
		{
			face = iter->second;
		}
	
		FT_Select_Charmap(face, FT_ENCODING_UNICODE);
		
		FT_Set_Char_Size(face, 0, font_size * 64, 300, 300);
		FT_Set_Pixel_Sizes(face, 0, font_size);
	
		UTF16CHAR *charcode = TCHAR_TO_UTF16(*single_char);
		FT_UInt glyph_index = FT_Get_Char_Index(face, *charcode);
		FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
		FT_Render_Glyph(face->glyph, FT_RENDER_MODE_NORMAL);

		FT_Bitmap bitmap = face->glyph->bitmap;
		int extsize = 50;
		int image_height = bitmap.rows + extsize * 2;
		int image_width = bitmap.width + extsize * 2;

		FontBitmap->Init(image_width,image_height,ERawImageFormat::G8);
		//FontBitmap->Create(image_width, image_height);
		
		int offsetx = extsize;
		int offsety = extsize;
		unsigned char c = 0;
		for (int row = 0; row < image_height; ++row)
		{
			for (int col = 0; col < image_width; ++col)
			{
				if (col < offsetx || row < offsety) {
					c = 0;
				} else {

					int x = col - offsetx;
					int y = row - offsety;

					if (x >= static_cast<int>(bitmap.width) || y >= static_cast<int>(bitmap.rows)) {
						c = 0;
					} else {
						c = bitmap.buffer[y * bitmap.width + x];
					}
				}

				void* Pointer= FontBitmap->GetPixelPointer(col,row);
				uint8* PixelPointer=static_cast<uint8*>(Pointer);
				*PixelPointer=c;
				//FontBitmap->SetRGB(col, row, c, c, c);
			}
		}

		{
			FT_Glyph_Metrics& Glyph_Metrics = face->glyph->metrics;
			// 空格的 Glyph_Metrics.width为0，后续运算会导致Metrics->AdvanceH为NaN.
			// 空格暂时认为width等于horiAdvance，height等于vertAdvance
			Glyph_Metrics.width = Glyph_Metrics.width == 0 ? Glyph_Metrics.horiAdvance : Glyph_Metrics.width;
			Glyph_Metrics.height = Glyph_Metrics.height == 0 ? Glyph_Metrics.vertAdvance : Glyph_Metrics.height;

			Metrics->AdvanceH = static_cast<float>(Glyph_Metrics.horiAdvance) / Glyph_Metrics.width;
			Metrics->AdvanceV = static_cast<float>(Glyph_Metrics.vertAdvance) / Glyph_Metrics.height;
			Metrics->BearingH = FVector2D(static_cast<float>(Glyph_Metrics.horiBearingX) / Glyph_Metrics.width,
				static_cast<float>(Glyph_Metrics.horiBearingY) / Glyph_Metrics.height);
			Metrics->BearingV = FVector2D(static_cast<float>(Glyph_Metrics.vertBearingX) / Glyph_Metrics.width,
				static_cast<float>(Glyph_Metrics.vertBearingY) / Glyph_Metrics.height);

			Metrics->BitmapTop = face->glyph->bitmap_top;
			Metrics->BitmapLeft = face->glyph->bitmap_left;
		}
	}
}
